//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <libpub.h>
#include <bo_cmds.h>

extern "C" {
unsigned long GetCxt(void *);
void Reboot(void *entry, unsigned long addr, int size);
unsigned long eldr_begin;
unsigned long eldr_end;
unsigned long eldr_size;
}

//==========================================================================
typedef struct {
    UINT32   CPSR;
    UINT32   LR, SP;
    UINT32   R0, R1, R2, R3, R4, R5, R6, R7;
    UINT32   R8, R9, R10, R11, R12;
    UINT32   PC;
}CXTINFO, *PCXTINFO;

static void __cdecl DumpCxt(PCXTINFO pCxt)
{
    printf("sp= %08x\tlr= %08x\tpc= %08x\tr0= %08x\tcpsr= %08x\n",
        pCxt->SP, pCxt->LR, pCxt->PC, pCxt->R0, pCxt->CPSR);
    printf("r1= %08x\tr2= %08x\tr3= %08x\tr4= %08x\n",
        pCxt->R1, pCxt->R2, pCxt->R3, pCxt->R4);
    printf("r5= %08x\tr6= %08x\tr7= %08x\tr8= %08x\n",
        pCxt->R5, pCxt->R6, pCxt->R7, pCxt->R8);
    printf("r9= %08x\tr10= %08x\tr11= %08x\tr12= %08x\n",
        pCxt->R9, pCxt->R10, pCxt->R11, pCxt->R12);
}

int Do_Cpu(char *param)
{
    TOUT(1, 1, printf("Cpu [%s]\n", param));

    CXTINFO info[2];
    PCXTINFO pCxt = info;
    GetCxt(pCxt+1);
    DumpCxt(pCxt);

    if (*param) {
        if (0 == Bo_MatchString(param, "dump")) {
        }
    }

    return 0;
}

#define RESERVED_CACHEABLE_REGION   0xffe00000

int Do_Cache(char *param)
{
    TOUT(1, 1, printf("Cache [%s]\n", param));

    static int s_switch;

    s_switch ^= 32768;

    // Global Clean or Invalidate The Data Cache
    ASM("mov    r0, #1024;"
        "1:"
        "mcr    p15, 0, %0, c7, c2, 5;"     // Allocate a line at the virtual
                                            //  address specified by %0
        "add    %0, %0, #32;"               // Increment the address in %0 to
                                            // the next cache line
        "subs   r0, r0, #1;"                // Decrement loop count
        "bne    1b;"
        : :"r"(RESERVED_CACHEABLE_REGION + s_switch) :"r0");

    ASM("mov    r0, #0;"
        "mcr    p15, 0, r0, c7, c10, 4;"    // drain write (& fill) buffer
        : : :"r0");

    ASM("mcr    p15, 0, r0, c7, c7, 0;"     // invalidate D & I cache
        : : :"r0");

    ASM("mrc    p15, 0, r0, c2, c0, 0;"     // arbitrary read of cp15
        "mov    r0, r0;"                    // wait for it
        "sub    pc, pc, #4;"
        : : :"r0");

    return 0;
}

int Do_Reboot(char *param)
{
    TOUT(1, 1, printf("reboot [%s]\n", param));

    unsigned long addr = 0xa3c00000;

    if (*param) {
        param = Bo_ParseInteger(param, &addr);
    }
    else return -1;

    unsigned long size = (unsigned long)&eldr_size;
    size = size * 2;//TODO: Need calu eldr size from header

    printf("reboot %x, %x, %x\n", &eldr_begin, addr, size);
    Reboot((void *)&eldr_begin, addr, size);
    return 0;
}

DECL_MAINCMD(Do_Cpu, "cpu {dump} -- ",  "...\n");
DECL_MAINCMD(Do_Reboot, "reboot {address}",  "load code from {address} before jump ...\n");
DECL_MAINCMD(Do_Cache, "cache {clean|invalid}",  "...\n");
